﻿using System;
using System.Collections.Generic;

namespace ModelViewer.TabsForModelviewer
{
    internal enum enumLineStatus
    {
        notChecked,
        HasNeighbor,
        HasNoNeighbor
    }

    internal class Line
    {
        #region Public Constructors

        public Line(int StartVertex, int EndVertex)
        {
            this.StartVertex = StartVertex;
            this.EndVertex = EndVertex;
            status = enumLineStatus.notChecked;
        }

        #endregion Public Constructors

        #region Public Properties

        public int EndVertex { get; set; }

        public int StartVertex { get; set; }

        public enumLineStatus status { get; set; }

        #endregion Public Properties

        #region Public Methods

        public override string ToString()
        {
            return string.Format("{0,-5} {1,-5} {2}", StartVertex, EndVertex, status.ToString());
        }

        #endregion Public Methods

        #region Internal Methods

        internal static bool CheckLine(Line line1, Line line2)
        {
            if (line1.StartVertex == line2.EndVertex &&
                line1.EndVertex == line2.StartVertex)
            {
                line1.status = enumLineStatus.HasNeighbor;
                line2.status = enumLineStatus.HasNeighbor;
                return true;
            }
            return false;
        }

        #endregion Internal Methods
    }

    internal class Polygon
    {
        #region Private Fields

        private readonly Line[] lines;

        #endregion Private Fields

        #region Public Constructors

        public Polygon(int polygonID, int VertexID1, int VertexID2, int VertexID3)
        {
            PolygonID = polygonID;
            lines = new Line[3];
            lines[0] = new Line(VertexID1, VertexID2);
            lines[1] = new Line(VertexID2, VertexID3);
            lines[2] = new Line(VertexID3, VertexID1);
        }

        #endregion Public Constructors

        #region Public Properties

        public int PolygonID { get; private set; }

        #endregion Public Properties

        #region Public Methods

        public override string ToString()
        {
            return string.Format("{0,-5} {1,3} {2,3} {3,3}", this.PolygonID.ToString(),
                this.lines[0].StartVertex, this.lines[1].StartVertex, this.lines[2].StartVertex);
        }

        #endregion Public Methods

        #region Internal Methods

        internal bool CheckAndUpdateLineStatus(Polygon poly)
        {
            foreach (var line1 in this.lines)
            {
                foreach (var line2 in poly.lines)
                {
                    if (line2.status == enumLineStatus.notChecked)
                        if (Line.CheckLine(line1, line2))
                            return true;
                }
            }
            return false;
        }

        internal void ResetLineStatus()
        {
            foreach (var item in lines)
            {
                item.status = enumLineStatus.notChecked;
            }
        }

        internal void SetLineStatusChecked()
        {
            foreach (var line in lines)
            {
                if (line.status == enumLineStatus.notChecked)
                    line.status = enumLineStatus.HasNoNeighbor;
            }
        }

        #endregion Internal Methods
    }

    internal class PolygonTools
    {
        #region Private Fields

        private List<Polygon> polygons;

        #endregion Private Fields

        #region Public Constructors

        public PolygonTools()
        {
            polygons = new List<Polygon>();
        }

        #endregion Public Constructors

        #region Internal Methods

        internal void AddPolygon(Polygon polygon)
        {
            this.polygons.Add(polygon);
        }

        internal List<int> GetJoinedPolygons(int startPolygonID)
        {
            bool neighborFound = false;
            List<Polygon> polygonsToCheck = new List<Polygon>();
            List<int> polygonIDsWhichLinkedToStart = new List<int>();
            polygonIDsWhichLinkedToStart.Add(startPolygonID);

            ResetLineStatus();

            // Get StartPolygon
            foreach (var item in this.polygons)
            {
                if (item.PolygonID == startPolygonID)
                {
                    polygonsToCheck.Add(item);
                    break;
                }
            }

            // Find neighbors
            do
            {
                neighborFound = false;
                List<Polygon> nextRoundPolyToCheck = new List<Polygon>();

                foreach (var polyToCheck in polygonsToCheck)
                {
                    foreach (var poly in this.polygons)
                    {
                        if (poly.PolygonID != polyToCheck.PolygonID)
                        {
                            neighborFound = polyToCheck.CheckAndUpdateLineStatus(poly);
                            if (neighborFound)
                            {
                                if (!polygonIDsWhichLinkedToStart.Contains(poly.PolygonID))
                                    polygonIDsWhichLinkedToStart.Add(poly.PolygonID);
                                else
                                    Console.WriteLine("poly already in list " + poly.PolygonID.ToString());

                                if (!nextRoundPolyToCheck.Contains(poly))
                                    nextRoundPolyToCheck.Add(poly);
                            }
                        }
                    }

                    polyToCheck.SetLineStatusChecked();
                }

                polygonsToCheck = nextRoundPolyToCheck;

                if (nextRoundPolyToCheck.Count > 0)
                    neighborFound = true;
            }
            while (neighborFound);

            polygonIDsWhichLinkedToStart.Sort();
            return polygonIDsWhichLinkedToStart;
        }

        #endregion Internal Methods

        #region Private Methods

        private void ResetLineStatus()
        {
            foreach (var item in polygons)
            {
                item.ResetLineStatus();
            }
        }

        #endregion Private Methods
    }

    internal class TestPolygon
    {
        #region Public Constructors

        public TestPolygon()
        {
            PolygonTools polygonTools = new PolygonTools();

            polygonTools.AddPolygon(new Polygon(1, 6, 7, 3));
            polygonTools.AddPolygon(new Polygon(2, 6, 3, 5));
            polygonTools.AddPolygon(new Polygon(3, 3, 4, 5));
            polygonTools.AddPolygon(new Polygon(4, 3, 1, 4));
            polygonTools.AddPolygon(new Polygon(5, 2, 1, 3));
            polygonTools.AddPolygon(new Polygon(6, 8, 2, 3));
            polygonTools.AddPolygon(new Polygon(7, 8, 3, 7));
            polygonTools.AddPolygon(new Polygon(8, 8, 7, 9));
            polygonTools.AddPolygon(new Polygon(9, 10, 12, 11));
            polygonTools.AddPolygon(new Polygon(10, 9, 7, 6));

            // joint last polygon to rest
            if (true)
            {
                polygonTools.AddPolygon(new Polygon(11, 10, 11, 1));
                polygonTools.AddPolygon(new Polygon(12, 1, 2, 10));
            }

            List<int> polygonIDs = polygonTools.GetJoinedPolygons(1);
        }

        #endregion Public Constructors
    }
}